package cz.vutbr.fit.xzemko01.tfmcbs.validation.validators;

import java.util.Map;

import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.DiagnosticChain;

import cz.vutbr.fit.xzemko01.tfmcbs.model.Delegate;
import cz.vutbr.fit.xzemko01.tfmcbs.model.Interface;
import cz.vutbr.fit.xzemko01.tfmcbs.model.Port;
import cz.vutbr.fit.xzemko01.tfmcbs.model.Relationship;
import cz.vutbr.fit.xzemko01.tfmcbs.validation.utils.DiagnosticBuilder;

public class DelegateValidator implements Validator<Delegate> {
	private static DelegateValidator delegateValidator;
	
	private Validator<Relationship> relationshipValidator;
	
	private DelegateValidator() {
		relationshipValidator = RelationshipValidator.getInstance();
	}
	
	public static Validator<Delegate> getInstance() {
		if(delegateValidator == null) {
			delegateValidator = new DelegateValidator();
		}
		return delegateValidator;		
	}
	
	@Override
	public boolean validate(Delegate delegate, DiagnosticChain diagnostics, Map<Object, Object> context) {
		boolean result = relationshipValidator.validate(delegate, diagnostics, context); 
		result &= validateDelegateHasSetInterface(delegate, diagnostics, context);
		result &= validateDelegateHasSetPort(delegate, diagnostics, context);
		result &= validateInterfaceAndPortInSameCompositeComponent(delegate, diagnostics, context);
		return result;
	}
	
	private boolean validateDelegateHasSetInterface(Delegate delegate, DiagnosticChain diagnostics, Map<Object, Object> context) {
		if(delegate.getInterface() == null) {
			Diagnostic diagnostic = new DiagnosticBuilder(delegate)
				.setMessage("Delegate \"" + delegate.getName() + "\" has not set interface.").build();
			
			diagnostics.add(diagnostic);
			return false;
		}
		return true;
	}
	
	private boolean validateDelegateHasSetPort(Delegate delegate, DiagnosticChain diagnostics, Map<Object, Object> context) {
		if(delegate.getPort() == null) {
			Diagnostic diagnostic = new DiagnosticBuilder(delegate)
				.setMessage("Delegate \"" + delegate.getName() + "\" has not set port.").build();
			
			diagnostics.add(diagnostic);
			return false;
		}
		return true;
	}
	
	private boolean validateInterfaceAndPortInSameCompositeComponent(Delegate delegate, DiagnosticChain diagnostics, Map<Object, Object> context) {
		Interface _interface = delegate.getInterface();
		Port port = delegate.getPort();
		
		if(_interface == null || port == null) {
			return true;
		}
		
		if(_interface.getContainer() != port.getComponent()) {
			Diagnostic diagnostic = new DiagnosticBuilder(delegate)
				.setMessage("Delegate \"" + delegate.getName() + "\" must have selected interface and port in same composite component.")
				.build();
		
			diagnostics.add(diagnostic);
			return false;
		}
		return true;
	}
}
